import MoveMap from "./MoveMap";
import MoveCamera from "./MoveCamera";
import { OPPSITE_DIR, OPPSITE, DIR } from "../cfw/tools/Define";
import { MoveType } from "./MoveConfig";
import { EVector2 } from "../engine/Math";
import { MoveHelper } from "./MoveHelper";
import { MoveBody } from "./MoveBody";
import { IMoveWorld } from "./IMoveWorld";
import MoveGround from "./MoveGround";

export class MoveWorld implements IMoveWorld {
    protected g: number = 1;
    protected objects: { [type: number]: MoveBody[] } = []
    protected map: MoveMap = new MoveMap()
    protected camera: MoveCamera = new MoveCamera()
    //摄像机跟随的物体
    protected moveBody: MoveBody = null;
    //无缝循环绘制的地面
    protected groundMgr: MoveGround = null;
    //震动时长
    protected shakeTime: number = 0

    setShakeTime(t: number) {
        this.shakeTime = t;
    }
    constructor() {
        this.camera.setMap(this.map)
    }

    getMoveBody(): MoveBody {
        return this.moveBody;
    }

    setMoveBody(obj: MoveBody) {
        this.moveBody = obj;
    }



    getG(): number {
        return this.g;
    }
    setG(g: number): void {
        this.g = g;
    }

    setGround(g: MoveGround) {
        this.groundMgr = g;
        this.groundMgr.setWorld(this)
    }


    setMap(map: MoveMap) {
        this.map = map;
        this.camera.setMap(this.map)
    }

    setCameraLeftTop() {
        this.setCameraPosition(0, 0)
    }

    setCamerLeftBottom() {
        this.setCameraPosition(0, this.map.getMapHeight() - this.camera.getHeight())
    }

    setCameraPosition(x: number, y: number) {
        this.camera.setX(x)
        this.camera.setY(y)
    }

    init(w: number, h: number, d: number = 0, cw: number, ch: number, cd: number) {
        this.map.init(w, h, d)
        this.camera.init(cw, ch, cd)
        for (let index = 0; index < MoveType.MAX; index++) {
            this.objects[index] = []
        }
    }



    getCamera() {
        return this.camera;
    }

    getMap() {
        return this.map;
    }

    add(obj: MoveBody) {
        obj.setWorld(this)
        let list = this.objects[obj.getMoveType()]
        if (!list) {
            list = []
            this.objects[obj.getMoveType()] = list;
            list.push(obj)
        } else {
            let index = list.indexOf(obj)
            if (index < 0) {
                list.push(obj)
            }
        }

        // console.log(' this.objects ', this.objects)

    }

    remove(obj: MoveBody) {
        let list = this.objects[obj.getMoveType()]
        if (list) {
            let index = list.indexOf(obj)
            if (index >= 0) {
                list.splice(index, 1)
            }
        }
    }


    update(dt: number) {
        for (let index = 0; index < MoveType.MAX; index++) {
            let list = this.objects[index]
            if (list) {
                for (let j = 0; j < list.length; j++) {
                    const element = list[j];
                    if (element.isActive()) {
                        this.updatePosition(element, dt)
                        this.camera.adjustPosition(element)
                    }
                }
            }

        }
        if (this.moveBody) {
            this.camera.scroll(this.moveBody.getX(), this.moveBody.getZ(), this.shakeTime)
            if (this.shakeTime > 0) {
                this.shakeTime -= dt;
                if (this.shakeTime < 0) {
                    this.shakeTime = 0;
                }
            }
        }

        if (this.groundMgr) {
            this.groundMgr.update(dt)
        }
    }

    /**
     * 
     * @param pos 屏幕坐标
     */
    getWorldPosition(pos: any) {
        let result = new EVector2()
        result.x = this.camera.getX() + pos.x;
        result.y = this.camera.getY() + pos.y;
        return result;
    }

    /**
     * 
     * @param npc 模拟弹力
     * @return 运动是否停止
     */
    protected doElasticity(npc: MoveBody): boolean {
        let n = npc.getElasticity()
        if (n != 0) {//有弹力数值
            let disy = npc.getSpeedY()
            if (disy != 0) {//y方向的速度不等于0
                let spy = n * -disy
                if (spy <= 1) {
                    npc.setSpeedY(0)
                    return true
                } else {
                    npc.setSpeedY(spy)
                }
            }
            return false;
        } else {
            return true;
        }

    }

    /**
     * 处理摩擦力
     * @param npc 
     */
    protected doFrictional(npc: MoveBody) {
        let sub = npc.getFrictional()
        if (sub != 0) {//有摩擦力

            let spx = npc.getSpeedX()
            if (spx != 0) {
                let dir = spx / Math.abs(spx)
                spx = spx - dir * sub
                // if (spx < 0) {
                //     spx = 0;
                // }
                npc.setSpeedX(spx)
            }
            let spz = npc.getSpeedZ()
            if (spz != 0) {
                let dir = spz / Math.abs(spz)
                spx = spx - dir * sub
                // if (spz < 0) {
                //     spz = 0;
                // }
                npc.setSpeedZ(spz)
            }
        }
    }
    /**
     * 不同的对象可走范围是不一样的。
     * @param npc 
     * @param lx 左边边界
     * @param width 可走宽度
     */
    updatePosition(npc: MoveBody, dt: number) {
        let spx = npc.getSpeedX()
        let n = npc.getElasticity()
        if (spx != 0) {
            let wpos = npc.getWorldPosition();
            let x = npc.getX()
            let z = npc.getZ();
            let y = npc.getY()
            let xx = x + spx * dt;
            let ground = this.getGround(wpos.x + spx * dt, wpos.y, wpos.z)
            if (!ground) {
                if (n != 0) {
                    spx = n * -spx
                    npc.setSpeedX(spx)
                } else {
                    npc.setSpeedX(0)
                }
            } else {
                x = xx
                npc.setX(x)
            }

        }



        let spz = npc.getSpeedZ()
        if (spz != 0) {
            let wpos = npc.getWorldPosition();
            let z = npc.getZ()
            let x = npc.getX();
            let y = npc.getY()
            let zz = z + spz * dt;
            let ground = this.getGround(wpos.x, wpos.y + spz * dt, wpos.z);
            if (!ground) {
                if (n != 0) {
                    spz = n * -spz
                    npc.setSpeedZ(spz)
                } else {
                    npc.setSpeedZ(0)
                }
                return;
            } else {
                z = zz
                npc.setZ(z)
            }

        }

        if (!npc.isOnGround()) {
            if (npc.isAwake()) {
                let y = npc.getY()
                let disy = npc.getSpeedY()
                let z = npc.getZ()
                let x = npc.getX();
                let ty = y + disy //* dt;
                if (npc.isOnPlane()) {
                    let plane: MoveBody = this.getPlane(npc, x, ty, z);
                    // console.log(' plane ', plane)
                    if (!plane) {
                        npc.setStandType(MoveType.OBJECT)
                    }
                }

                if (!npc.isOnPlane()) {
                    if (ty < 0) {
                        ty = 0
                    } else if (ty > 0) {
                        npc.setSpeedY(disy - this.g)
                    }
                    if (ty == 0) {//在地面上
                        if (this.doElasticity(npc)) {
                            npc.setStandType(MoveType.GROUND)
                        }
                    } else {
                        let plane: MoveBody = this.getPlane(npc, x, ty, z);
                        // console.log(' plane ', plane)
                        if (plane) {
                            let collide = npc.getCollide()
                            if (collide) {
                                let index = npc.getB().indexOf(plane)
                                if (index < 0) {
                                    npc.getB().push(plane)
                                    collide.onCollideEnter(npc, plane)
                                }
                            }
                            // console.log(' plane ', plane)

                            if (disy <= 0) {//如果物理在下落
                                let dir: DIR = MoveHelper.getDir(plane, npc)
                                // console.log(' dir == ', dir)
                                if (dir == DIR.UP) {
                                    ty = plane.getTop()
                                    if (this.doElasticity(npc)) {
                                        npc.setStandType(MoveType.PLANE)
                                    }
                                }
                            }
                        }
                    }
                    npc.setY(ty)
                }

            }
        }


        if (npc.isStopDrop()) {//在地面或者平台上
            this.doFrictional(npc)
        }



    }


    /**
     * 判断移动的物体是否在给定的形状中。
     * @param x 
     * @param y 
     * @param z 
     * @returns 
     */
    getGround(x: number, y: number, z: number): MoveBody {
        let list = this.objects[MoveType.GROUND]
        for (let index = list.length - 1; index >= 0; index--) {
            const element = list[index];
            // if (obj != element) {
            // console.log('element.getTop() ', element.getTop())
            if (MoveHelper.pointInPolygonByWorldPosition(element, x, y, z)) {
                return element
            }
            // }
        }
        return null;
    }

    getPlane(npc: MoveBody, x: number, y: number, z: number): MoveBody {
        // console.log(' this.planes.length  ', this.planes.length, 'y', y)
        let topCollide = npc.getTopCollide()
        let list = this.objects[MoveType.PLANE]
        for (let index = list.length - 1; index >= 0; index--) {
            const element = list[index];

            if (topCollide && !npc.isStopDrop()) {
                if (MoveHelper.pointTopRange(element, npc.getX(), npc.getY(), npc.getZ())) {
                    topCollide.onTopEnter(element)
                }
            }
            if (MoveHelper.pointInPolygon(element, x, y, z)) {
                return element
            } else {
                let idx = npc.getB().indexOf(element)
                if (idx >= 0) {
                    npc.getB().splice(idx, 1)
                }
            }
            // if (obj != element) {
            // let flag = Utils.isRecctCollideRect3(npc.getLeft(), npc.getRight(), npc.getTop(), npc.getBottom(),
            //     element.getLeft(), element.getRight(), element.getTop(), element.getBottom())
            // if (flag) {
            //     return element;
            // } else {
            //     let idx = npc.b.indexOf(element)
            //     if (idx >= 0) {
            //         npc.b.splice(idx, 1)
            //     }
            // }
            // }

        }
        // if (topCollide) {
        //     topCollide.onTopExit()
        // }
        return null;
    }
}